#include "Assembler.h"

program* assemble(FILE* f)
{
    program* coms = (program*) calloc(1, sizeof(program));
    int len = 0,
        number = 0;

    char temp[10] = "";
    int temp_exist = 0;


    while(strcmp("Quit", temp))
    {
        if(!temp_exist)
            fscanf(f, "%s", temp);
        else
            temp_exist = 0;

        //valueType here is used for destination
        if(!strcmp("mov", temp))
        {
            fscanf(f, "%s", temp);
            if((number = numVar(coms, temp)) >= 0)
            {
                coms->com[coms->length].command = MOV;
                coms->com[coms->length].valueType = number;
                fscanf(f, "%lg", &coms->com[coms->length].value);
                coms->length++;
            }
            else
            {
                fprintf(f, "Syntax error. Variable wasn't declared use dec <name> for declaration.");
                free(coms);
                return NULL;
            }
        }
        else if (!strcmp("push", temp))
        {
            fscanf(f, "%s", temp);
            coms->com[coms->length].command = PUSH;
            if ((number = numVar(coms, temp)) >= 0)
            {
                coms->com[coms->length].valueType = VARIABLE;
                coms->com[coms->length].value     = (double) number;

            }
            else
            {
                coms->com[coms->length].valueType = NUMBER;
                sscanf(temp, "%lg", &coms->com[coms->length].value);
            }
            coms->length++;

        }

        else if(!strcmp("pop", temp))
        {
            fscanf(f, "%s", temp);
            coms->com[coms->length].command = POP;
            if ((number = numVar(coms, temp)) >= 0)
            {
                coms->com[coms->length].valueType = VARIABLE;
                coms->com[coms->length].value     = (double) number;
            }
            else
                temp_exist = 1;
            ++coms->length;
        }

        else if(!strcmp("add", temp))
            {
                coms->com[coms->length].command = ADD;
                ++coms->length;
            }

        else if(!strcmp("sqrt", temp))
            {
                coms->com[coms->length].command = SQRTI;
                ++coms->length;
            }

        else if(!strcmp("sub", temp))
            {
                coms->com[coms->length].command = SUB;
                ++coms->length;
            }

        else if(!strcmp("mul", temp))
            {
                coms->com[coms->length].command = MUL;
                ++coms->length;
            }

        else if(!strcmp("div", temp))
            {
                coms->com[coms->length].command = DIVI;
                ++coms->length;
            }

        else if(!strcmp("dub", temp))
            {
                coms->com[coms->length].command = DUB;
                ++coms->length;
            }

        else if(!strcmp("ja", temp))
        {
            fscanf(f, "%s", temp);
            coms->com[coms->length].command = JA;
            coms->com[coms->length].value   = (double) numLabel(coms, temp);
            coms->length++;
        }
        else if(!strcmp("jb", temp))
        {
            fscanf(f, "%s", temp);
            coms->com[coms->length].command = JB;
            coms->com[coms->length].value   = (double) numLabel(coms, temp);
            coms->length++;
        }
        else if(!strcmp("je", temp))
        {
            fscanf(f, "%s", temp);
            coms->com[coms->length].command = JE;
            coms->com[coms->length].value   = (double) numLabel(coms, temp);
            coms->length++;
        }
        else if(!strcmp("dec", temp))
        {
            fscanf(f, "%s", temp);
            strcpy(coms->var[coms->numofVar].name, temp);
            coms->numofVar++;
        }
        //!for function declaration
        else if(!strcmp("func", temp))
        {
            coms->com[coms->length].command = FUNC;
            coms->length++;
            fscanf(f, "%s", temp);
            strcpy(coms->labels[coms->numofLabels].name, temp);
            coms->labels[coms->numofLabels].position = coms->length;
            coms->numofLabels++;
        }
        else if(!strcmp("skip", temp))
        {
            coms->com[coms->length].command = SKIP;
            coms->length++;
        }
        else if(!strcmp("calla", temp))
        {
            coms->com[coms->length].command = CALLA;
            fscanf(f,"%s", temp);
            if((number = numLabel(coms, temp)) == -1)
            {
                printf("ERROR:FUNCTION WASN'T DECLARED BEFORE CALL");
                return NULL;
            }
            coms->com[coms->length].value   = coms->labels[number].position;
            coms->length++;
        }
        else if(!strcmp("call", temp))
        {
            coms->com[coms->length].command = CALL;
            fscanf(f, "%s", temp);
            if((number = numLabel(coms, temp)) == -1)
            {
                printf("ERROR:FUNCTION WASN'T DECLARED BEFORE CALL");
                return NULL;
            }
            coms->com[coms->length].value = coms->labels[number].position;
            coms->length++;
        }
        else
        {
            strcpy(coms->labels[coms->numofLabels].name, temp);
            coms->labels[coms->numofLabels].position = coms->length;
            coms->numofLabels++;
        }
    }
    return coms;
}

int numVar(program* prgr, char value[])
{
    int i = 0;
    while(i < prgr->numofVar)
    {
        if(!strcmp(value, prgr->var[i].name))
            break;
        i++;
    }
    if (i == prgr->numofVar)
        return -1;
    else
        return i;
}
int numLabel(program* prgr, char value[])
{
    int i = 0;
    while(i < prgr->numofLabels)
    {
        if(!strcmp(value, prgr->labels[i].name))
            break;
        i++;
    }
    if (i == prgr->numofLabels)
        return -1;
    else
        return i;
}
void printCommands(const program* prgr)
{
    if(prgr)
    {
        printf("Variables: %d\n", prgr->numofVar);
        for(int i = 0; i < prgr->numofVar; i++)
        {
            printf("  Var[%d]: <%s>\n", i, prgr->var[i].name);
        }
        printf("Labels: %d", prgr->numofLabels);
        for(int i = 0; i < prgr->numofLabels; i++)
        {
            printf("  Label[%d]: <%s>; position: %d\n", i, prgr->labels[i].name, prgr->labels[i].position);
        }
        printf("Commands. Length: %d\n", prgr->length);
        for(int i = 0; i < prgr->length; i++)
        {
            printf("  Command[%d]: commandNumber[%d]; valueType[%d]; value[%lg];\n", i,
            prgr->com[i].command,
            prgr->com[i].valueType, prgr->com[i].value);
        }
    }
}
